﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using MobileSales.Server.Database;
using MobileSales.Common.Logger;
using System.Runtime.Serialization.Json;
using System.IO;

namespace MobileSales.Server.Services
{
    public class ClientService : ServiceBase, IClientService
    {
        #region Client management

        #region GetClient
        public Model.Clients.Client GetClient(int clientId)
        {
            //byte[] byteArray = Encoding.UTF8.GetBytes("{\"City\":\"zxc\",\"Zipcode\":\"zxc\",\"Fax\":\"zxc\",\"Group\":{\"Name\":\"Zwykli klienci\",\"Id\":1,\"Discount\":0.2},\"Street\":\"zxc\",\"Info\":\"zxc\",\"Info2\":\"\",\"IsSupplier\":false,\"Name\":\"zxc\",\"Name2\":\"zxc\",\"Nip\":\"zxc\",\"Phone\":\"zxc\",\"Debts\":0.0,\"Id\":0,\"Params\":[{\"Key\":{\"DefaultValue\":\"True\",\"DisplayName\":\"Wartość\",\"FieldType\":\"Boolean\",\"ParamType\":\"Client\",\"Name\":\"wartosc\",\"MaxLength\":0,\"IsRequired\":false,\"IsReadOnly\":false,\"Id\":14},\"Value\":\"true\"}]}");
            //MemoryStream stream = new MemoryStream( byteArray ); 
            //object o = new DataContractJsonSerializer(typeof(Model.Clients.Client)).ReadObject(stream);


            this.ValidateToken();
            Client dbClient = entities.Clients.Where(x => x.ClientId.Equals(clientId)).FirstOrDefault();
            if (dbClient != null)
            {
                Model.Clients.Client client = new Model.Clients.Client();
                this.FillClient(dbClient, ref client);
                return client;
            }
            else
                CLogger.LogDebug("Client not found");
            return null;
        }
        #endregion

        #region StoreClient
        public void StoreClient(Model.Clients.Client client)
        {
            this.ValidateToken();
            Client dbClient = null;
            if (client.Id != 0)
            {
                dbClient = entities.Clients.Where(x => x.ClientId.Equals(client.Id)).FirstOrDefault();
                if (dbClient == null)
                    this.Raise("Client not found");
            }
            else
            {
                dbClient = new Client();
            }

            dbClient.City = client.City;
            dbClient.Debts = client.Debts;
            dbClient.Fax = client.Fax;
            dbClient.ClientGroupId = (client.Group != null) ? (int?)client.Group.Id : null;
            dbClient.Info = client.Info;
            dbClient.Info2 = client.Info2;
            dbClient.IsSupplier = client.IsSupplier;
            dbClient.LastVisitTime = client.LastVisitTime;
            dbClient.Name = client.Name;
            dbClient.Name2 = client.Name2;
            dbClient.Nip = client.Nip;
            dbClient.Phone = client.Phone;
            dbClient.Street = client.Street;
            dbClient.Zipcode = client.Zipcode;
            if (client.Id == 0)
            {
                entities.Clients.AddObject(dbClient);
            }
            entities.SaveChanges();
            this.StoreClientParams(dbClient.ClientId, client.Params);
            this.NotifyAll(Util.ServiceType.ClientService, "GetClient", dbClient.ClientId);
        }
        #endregion

        #region DeleteClient
        public void DeleteClient(int clientId)
        {
            this.ValidateToken();
            Client dbClient = entities.Clients.Where(x => x.ClientId.Equals(clientId)).FirstOrDefault();
            if (dbClient != null)
            {
                IEnumerable<ClientHasParam> clientParams = entities.ClientHasParams.Where( x=> x.ClientId.Equals(clientId));
                if (clientParams != null)
                {
                    foreach(ClientHasParam cp in clientParams)
                        entities.ClientHasParams.DeleteObject(cp);
                }
                entities.Clients.DeleteObject(dbClient);
                entities.SaveChanges();
                this.NotifyAll(Util.ServiceType.ClientService, "DeleteClient", clientId);
            }
            else
                this.Raise("Client not found");
        }
        #endregion

        #region GetClientList
        public IEnumerable<Model.Clients.Client> GetClientList()
        {
            this.ValidateToken();
            IEnumerable<Client> dbClients = entities.Clients;
            if (dbClients != null)
            {
                List<Model.Clients.Client> list = new List<Model.Clients.Client>();
                foreach (var dbClient in dbClients)
                {
                    Model.Clients.Client client = new Model.Clients.Client();
                    this.FillClient(dbClient, ref client);
                    list.Add(client);
                }
                return list;
            }
            else
                CLogger.LogDebug("Could not get client list");
            return null;
        }
        #endregion

        #region GetClientListByGroup
        public IEnumerable<Model.Clients.Client> GetClientListByGroup(int groupId)
        {
            this.ValidateToken();
            IEnumerable<Client> dbClients = entities.Clients.Where(x => x.ClientGroupId.Equals(groupId));
            if (dbClients != null)
            {
                List<Model.Clients.Client> list = new List<Model.Clients.Client>();
                foreach (var dbClient in dbClients)
                {
                    Model.Clients.Client client = new Model.Clients.Client();
                    this.FillClient(dbClient, ref client);
                    list.Add(client);
                }
                return list;
            }
            else
                CLogger.LogDebug("Could not get client list by group");
            return null;
        }
        #endregion

        #region GetClientNameList
        public IDictionary<int, string> GetClientNameList()
        {
            this.ValidateToken();
            IEnumerable<Client> dbClients = entities.Clients;
            if (dbClients != null)
            {
                Dictionary<int, string> dict = new Dictionary<int, string>();
                foreach (var dbClient in dbClients)
                {
                    dict.Add(dbClient.ClientId, dbClient.Name);
                }
                return dict;
            }
            else
                CLogger.LogDebug("Could not get client name list");
            return null;
        } 
        #endregion

        #region FillClient
        private void FillClient(Client sourceCli, ref Model.Clients.Client destCli)
        {
            destCli.City = sourceCli.City;
            destCli.Debts = sourceCli.Debts;
            destCli.Fax = sourceCli.Fax;
            destCli.Group = sourceCli.ClientGroupId.HasValue ? this.GetClientGroup(sourceCli.ClientGroupId.Value) : null;
            destCli.Id = sourceCli.ClientId;
            destCli.Info = sourceCli.Info;
            destCli.Info2 = sourceCli.Info2;
            destCli.IsSupplier = sourceCli.IsSupplier;
            destCli.LastVisitTime = sourceCli.LastVisitTime;
            destCli.Name = sourceCli.Name;
            destCli.Name2 = sourceCli.Name2;
            destCli.Nip = sourceCli.Nip;
            destCli.Phone = sourceCli.Phone;
            destCli.Street = sourceCli.Street;
            destCli.Zipcode = sourceCli.Zipcode;
            destCli.Params = this.GetClientParams(sourceCli.ClientId);
        }
        #endregion

        #region GetClientParams
        public Dictionary<Model.Params.Param, string> GetClientParams(int clientId)
        {
            IEnumerable<ClientHasParam> dbClientHasParams = entities.ClientHasParams.Where(x => x.ClientId.Equals(clientId));
            if (dbClientHasParams != null)
            {
                Dictionary<Model.Params.Param, string> dict = new Dictionary<Model.Params.Param, string>();
                foreach (var dbClientHasParam in dbClientHasParams)
                {
                    Model.Params.Param param = this.GetParam(dbClientHasParam.ParamId);
                    if (param != null)
                    {
                        dict.Add(param, dbClientHasParam.Value);
                    }
                    else
                        this.Raise("An error occured during getting some parameters");
                }
                return dict;
            }
            else
            {
                CLogger.LogDebug("Could not get parameters for client (id:{0})", clientId);
            }
            return null;
        }
        #endregion

        #region StoreClientParams
        public void StoreClientParams(int clientId, Dictionary<Model.Params.Param, string> paramDict)
        {
            Client dbClient = entities.Clients.Where(x => x.ClientId.Equals(clientId)).FirstOrDefault();
            if (dbClient == null)
            {
                this.Raise("Update failed! Cannot store employee params");
            }

            IEnumerable<ClientHasParam> dbClientParamList = dbClient.ClientHasParams;
            foreach (var param in paramDict.Keys)
            {
                ClientHasParam dbClientParam = dbClientParamList.Where(x => x.ParamId.Equals(param.Id)).FirstOrDefault();
                bool exist = true;
                if (dbClientParam == null)
                {
                    exist = false;
                    dbClientParam = new ClientHasParam();
                }

                dbClientParam.ParamId = param.Id;
                dbClientParam.ClientId = clientId;
                if (paramDict[param] == null) continue;
                dbClientParam.Value = paramDict[param].ToString();

                if (!exist)
                {
                    dbClient.ClientHasParams.Add(dbClientParam);
                }
            }
            entities.SaveChanges();

            dbClientParamList = dbClient.ClientHasParams;
            List<ClientHasParam> toRemove = new List<ClientHasParam>();
            foreach (var dbClientParam in dbClientParamList)
            {
                if (!paramDict.Keys.Select(x => x.Id).Contains(dbClientParam.ParamId))
                {
                    toRemove.Add(dbClientParam);
                }
            }
            foreach (var dbEmployeeParam in toRemove)
            {
                dbClient.ClientHasParams.Remove(dbEmployeeParam);
            }
            entities.SaveChanges();
        }
        #endregion

        #endregion

        #region Client group management

        #region GetClientGroup
        public Model.Clients.ClientGroup GetClientGroup(int clientGroupId)
        {
            this.ValidateToken();
            ClientGroup dbGroup = entities.ClientGroups.Where(x => x.GroupId.Equals(clientGroupId)).FirstOrDefault();
            if (dbGroup != null)
            {
                Model.Clients.ClientGroup group = new Model.Clients.ClientGroup()
                {
                    Discount = dbGroup.Discount,
                    Id = dbGroup.GroupId,
                    Name = dbGroup.Name
                };
                return group;
            }
            else
                CLogger.LogDebug("Group not found");
            return null;
        }
        #endregion

        #region GetClientGroupList
        public IEnumerable<Model.Clients.ClientGroup> GetClientGroupList()
        {
            this.ValidateToken();
            IEnumerable<ClientGroup> dbGroups = entities.ClientGroups;
            if (dbGroups != null)
            {
                List<Model.Clients.ClientGroup> list = new List<Model.Clients.ClientGroup>();
                foreach (var dbGroup in dbGroups)
                {
                    Model.Clients.ClientGroup group = new Model.Clients.ClientGroup()
                    {
                        Discount = dbGroup.Discount,
                        Id = dbGroup.GroupId,
                        Name = dbGroup.Name
                    };
                    list.Add(group);
                }
                return list;
            }
            else
                CLogger.LogDebug("Could not get group list");
            return null;
        }
        #endregion

        #region StoreClientGroup
        public void StoreClientGroup(Model.Clients.ClientGroup group)
        {
            this.ValidateToken();
            ClientGroup dbGroup = null;
            if (group.Id != 0)
            {
                dbGroup = entities.ClientGroups.Where(x => x.GroupId.Equals(group.Id)).FirstOrDefault();
                if (dbGroup == null)
                {
                    this.Raise("Group not found");
                }
            }
            else
            {
                dbGroup = new ClientGroup();
            }
            dbGroup.Name = group.Name;
            dbGroup.Discount = group.Discount;

            if (group.Id == 0)
            {
                entities.ClientGroups.AddObject(dbGroup);
            }
            entities.SaveChanges();
            this.NotifyAll(Util.ServiceType.ClientService, "GetClientGroup", dbGroup.GroupId);
        }
        #endregion

        #region DeleteClientGroup
        public void DeleteClientGroup(int clientGroupId)
        {
            this.ValidateToken();
            ClientGroup dbGroup = entities.ClientGroups.Where(x => x.GroupId.Equals(clientGroupId)).FirstOrDefault();
            if (dbGroup != null)
            {
                entities.ClientGroups.DeleteObject(dbGroup);
                entities.SaveChanges();
                this.NotifyAll(Util.ServiceType.ClientService, "DeleteClientGroup", clientGroupId);
            }
            else
                this.Raise("Group not found");
        }
        #endregion

        #endregion
    }
}
